﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Engine.Components
{
    
   public class ComponentManager
    {
        NOWAEngine _game;
        bool _init = false;
        Dictionary<string, IEngineComponent> indexator;
        List<IEngineComponent> needAdd;
        List<IEngineComponent> validateAdd;
        public bool Init { get { return _init; } }
        public ComponentManager(NOWAEngine game)
        {
            _game = game;
            _game.Components.ComponentAdded += new EventHandler<Microsoft.Xna.Framework.GameComponentCollectionEventArgs>(Components_ComponentAdded);
            _game.Components.ComponentRemoved += new EventHandler<Microsoft.Xna.Framework.GameComponentCollectionEventArgs>(Components_ComponentRemoved);
            indexator = new Dictionary<string, IEngineComponent>(0);
            needAdd = new List<IEngineComponent>(0);
            validateAdd = new List<IEngineComponent>(0);
        }

        void Components_ComponentRemoved(object sender, Microsoft.Xna.Framework.GameComponentCollectionEventArgs e)
        {
            IEngineComponent comp = ((IEngineComponent)(e.GameComponent));
            if (comp.NotDel)
            {
                validateAdd.Add(comp);
                _game.Components.Insert(comp.ID, comp);
                throw Helpers.Errors.getExceptionByCode(2, comp); //except try delete no del component
            }
            else
            {
                if (indexator.ContainsKey(comp.Name))
                {
                    indexator.Remove(comp.Name);
                }
            }
            for (int i = 0; i < _game.Components.Count; i++)
            {
                ((IEngineComponent)(_game.Components[i])).ID=i;
               
            }
        }
        void Components_ComponentAdded(object sender, Microsoft.Xna.Framework.GameComponentCollectionEventArgs e)
        {
            IEngineComponent comp = (IEngineComponent)e.GameComponent;
            comp.ID = ((Microsoft.Xna.Framework.GameComponentCollection)(sender)).Count - 1;

            if (validateAdd.Contains(comp))
            {
                
           
            if (indexator.ContainsKey(comp.Name))
            {
                indexator[comp.Name]=comp;
            }
            else
            {
                indexator.Add(comp.Name, comp);
            }
            validateAdd.Remove(comp);
             }
            else
            {
                string cashname = comp.Name;
                comp.Name = "need_del_component_fatal";
               
                comp.Extend();
                indexator.Add(comp.Name, comp);
                _game.Components.Remove(comp);
                comp.Name = cashname;
                throw Helpers.Errors.getExceptionByCode(3, comp); //except try add component instance
            }
        }

        public void Close()
        {
           
            _game.Components.ComponentAdded -=  new EventHandler<Microsoft.Xna.Framework.GameComponentCollectionEventArgs>(Components_ComponentAdded);
            _game.Components.ComponentRemoved -= new EventHandler<Microsoft.Xna.Framework.GameComponentCollectionEventArgs>(Components_ComponentRemoved);
        }
        public void init()
        {
            GameClass.LevelTable.InitTable();
            InputManager inputManager = new InputManager(_game,this,true);
            validateAdd.Add(inputManager);
            GameManager gameManager = new GameManager(_game, this, true);
            validateAdd.Add(gameManager);
            CameraManager cameraManager = new CameraManager(_game, this, true);
            validateAdd.Add(cameraManager);
            SceneManager sceneManager = new SceneManager(_game, this, true);
            validateAdd.Add(sceneManager);

            /// добовляем базовые компоненты по порядку использования

            _game.Components.Add(inputManager);
            _game.Components.Add(cameraManager);
            _game.Components.Add(gameManager);          
            _game.Components.Add(sceneManager);

            //добовляем в конец доп компоненты
            for (int i = 0; i < needAdd.Count; i++)
            {
                if (indexator.ContainsKey(needAdd[i].Name))
                {
                    throw Helpers.Errors.getExceptionByCode(1, needAdd[i]); // name component exist
                }
                else
                {
                    _game.Components.Add(needAdd[i]);
                }
            }

            needAdd.Clear();
            _init = true;
        }
        public void AddExtendComponent(IEngineComponent component)
        {
            if (indexator.ContainsKey(component.Name))
            {
                throw Helpers.Errors.getExceptionByCode(1,component); // name component exist
            }
            else
            {
                component.Extend();
                if (_init)
                {
                    validateAdd.Add(component);
                    _game.Components.Add(component);
                }
                else
                {
                    validateAdd.Add(component);
                    needAdd.Add(component);
                }
            }
        }
        public void RemoveComponent(IEngineComponent component)
        {
            if (indexator.ContainsValue(component)&& !component.NotDel)
            {
                _game.Components.Remove(component);
            }
            if (component.NotDel)
            {
               throw Helpers.Errors.getExceptionByCode(2,component);
            }
        }
        public void RemoveComponent(string NameComponent)
        {
            if (indexator.ContainsKey(NameComponent))
            {
                if (!indexator[NameComponent].NotDel)
                {
                     _game.Components.Remove(indexator[NameComponent]);
                }
                else
                {
                    throw Helpers.Errors.getExceptionByCode(2, indexator[NameComponent]); //except try delete no del component
                }
               
            }
        }
        public dynamic GetComponent(string Name)
        {
            if (indexator.ContainsKey(Name))
            {
                return indexator[Name];
            }
            else
            {
                return null;
            }
        }
        public IEngineComponent[] GetByType(Type type)
        {
            List<IEngineComponent> temp = new List<IEngineComponent>();
            foreach (var item in indexator)
            {
                if (item.Value.GetType()==type)
                {
                    temp.Add(item.Value);
                }
            }

            if (temp.Count>0)
            {
                return temp.ToArray();
            }
            else
            {
                return null;
            }

        }
    }
}
